using Digitalmes.Application.Services;
using Digitalmes.Domain.Entities.Mes.Productions;
using Digitalmes.Domain.Entities.Mes.Qualities;

namespace Digitalmes.Application.Mes.Productions.Products.Commands;

/// <summary>
/// 产品报废命令。
/// </summary>
/// <param name="Id">产品状态 Id</param>
/// <param name="ScrapCategory">报废分类</param>
/// <param name="ScrapCategoryName">报废分类名称</param>
/// <param name="ScrapReason">报废原因</param>
public sealed record ScrapProductCommand(
    long Id,
    string? ScrapCategory,
    string? ScrapCategoryName,
    string? ScrapReason) : IRequest<IResult<bool>>;

internal sealed class ScrapProductCommandHandler(
    IRepository<ProdCurrentState> repo,
    IRepository<QcScrapInfo> scrapRepo,
    IWorkOrderService workOrderService) : IRequestHandler<ScrapProductCommand, IResult<bool>>
{
    public async Task<IResult<bool>> Handle(ScrapProductCommand request, CancellationToken cancellationToken)
    {
        var currentState = await repo.GetByIdAsync(request.Id, cancellationToken);
        if (currentState == null)
        {
            return Result.Failure("未找到要更新的产品");
        }

        if (currentState.Status is not PassEnum.NG and not PassEnum.ForceNG)
        {
            return Result.Failure("产品只有在不合格状态下才能报废");
        }

        // 已开返工单的产品不能报废处理
        if (currentState.InReworkDocId > 0)
        {
            return Result.Failure("已开返工单的产品不能报废处理");
        }

        currentState.Status = PassEnum.Scrap;
        var ok = await repo.UpdateAsync(currentState, m => new
        {
            m.Status,
        }, cancellationToken);

        // 更新工单报废数量
        if (ok && !string.IsNullOrEmpty(currentState.Wo))
        {
            await workOrderService.IncrementScrapQtyAsync(currentState.Wo, cancellationToken);
        }

        // 新增报废信息
        QcScrapInfo scrapInfo = new()
        {
            Sn = currentState.Sn,
            ProductId = currentState.ProductId,
            ProductCode = currentState.ProductCode,
            Wo = currentState.Wo,
            LineId = currentState.LineId,
            OperationId = currentState.OperationId,
            OperationCode = currentState.OperationCode,
            WorkstationId = currentState.WorkstationId,
            WorkstationCode = currentState.WorkstationCode,
            ScrapCategory = request.ScrapCategory,
            ScrapCategoryName = request.ScrapCategoryName,
            ScrapReason = request.ScrapReason,
        };
        await scrapRepo.InsertAsync(scrapInfo, cancellationToken);

        return Result.From(ok);
    }
}
